package com.kwdb.sdk;

import com.kwdb.sdk.config.ClientConfig;
import com.kwdb.sdk.data.DataPoint;
import com.kwdb.sdk.grpc.KWDBGrpcClient;
import com.kwdb.sdk.query.QueryBuilder;
import com.kwdb.sdk.query.QueryResult;
import com.kwdb.sdk.serialization.LineProtocolParser;
import com.kwdb.sdk.batch.BatchWriter;
import com.kwdb.sdk.exception.KWDBException;

import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * KWDB客户端主类 - 基于gRPC的高性能SDK
 * 
 * 架构层次：
 * - API封装层：提供简洁易用的API接口
 * - 序列化层：处理Telegraf Line Protocol格式
 * - 通信层：基于gRPC的长连接通信
 * - 协议层：统一的gRPC服务接口
 */
public class KWDBClient {
    
    private final ClientConfig config;
    private final KWDBGrpcClient grpcClient;
    private final BatchWriter batchWriter;
    private final LineProtocolParser parser;
    private final ExecutorService executorService;
    private volatile boolean connected = false;
    
    /**
     * 构造函数
     * @param config 客户端配置
     */
    public KWDBClient(ClientConfig config) {
        this.config = config;
        this.grpcClient = new KWDBGrpcClient(config);
        this.batchWriter = new BatchWriter(config, grpcClient);
        this.parser = new LineProtocolParser();
        this.executorService = Executors.newFixedThreadPool(config.getThreadPoolSize());
    }
    
    /**
     * 连接到KWDB服务器
     * @throws KWDBException 连接异常
     */
    public void connect() throws KWDBException {
        try {
            grpcClient.connect();
            batchWriter.start();
            connected = true;
        } catch (Exception e) {
            throw new KWDBException("连接失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 断开连接
     */
    public void disconnect() {
        if (connected) {
            batchWriter.stop();
            grpcClient.disconnect();
            executorService.shutdown();
            connected = false;
        }
    }
    
    /**
     * 写入单条数据点
     * @param dataPoint 数据点
     * @throws KWDBException 写入异常
     */
    public void write(DataPoint dataPoint) throws KWDBException {
        if (!connected) {
            throw new KWDBException("客户端未连接");
        }
        
        try {
            batchWriter.addDataPoint(dataPoint);
        } catch (Exception e) {
            throw new KWDBException("写入失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 异步写入单条数据点
     * @param dataPoint 数据点
     * @return CompletableFuture
     */
    public CompletableFuture<Void> writeAsync(DataPoint dataPoint) {
        return CompletableFuture.runAsync(() -> {
            try {
                write(dataPoint);
            } catch (KWDBException e) {
                throw new RuntimeException(e);
            }
        }, executorService);
    }
    
    /**
     * 批量写入数据点
     * @param dataPoints 数据点列表
     * @throws KWDBException 写入异常
     */
    public void writeBatch(List<DataPoint> dataPoints) throws KWDBException {
        if (!connected) {
            throw new KWDBException("客户端未连接");
        }
        
        try {
            grpcClient.writeBatch(dataPoints);
        } catch (Exception e) {
            throw new KWDBException("批量写入失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 异步批量写入数据点
     * @param dataPoints 数据点列表
     * @return CompletableFuture
     */
    public CompletableFuture<Void> writeBatchAsync(List<DataPoint> dataPoints) {
        return CompletableFuture.runAsync(() -> {
            try {
                writeBatch(dataPoints);
            } catch (KWDBException e) {
                throw new RuntimeException(e);
            }
        }, executorService);
    }
    
    /**
     * 流式写入数据点
     * @param dataPoints 数据点列表
     * @return CompletableFuture
     */
    public CompletableFuture<Void> writeStreamAsync(List<DataPoint> dataPoints) {
        return CompletableFuture.runAsync(() -> {
            try {
                grpcClient.writeStream(dataPoints);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }, executorService);
    }
    
    /**
     * 执行SQL查询
     * @param sql SQL语句
     * @return 查询结果
     * @throws KWDBException 查询异常
     */
    public QueryResult query(String sql) throws KWDBException {
        if (!connected) {
            throw new KWDBException("客户端未连接");
        }
        
        try {
            return grpcClient.query(sql);
        } catch (Exception e) {
            throw new KWDBException("查询异常: " + e.getMessage(), e);
        }
    }
    
    /**
     * 异步执行SQL查询
     * @param sql SQL语句
     * @return CompletableFuture<QueryResult>
     */
    public CompletableFuture<QueryResult> queryAsync(String sql) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                return query(sql);
            } catch (KWDBException e) {
                throw new RuntimeException(e);
            }
        }, executorService);
    }
    
    /**
     * 流式查询
     * @param sql SQL语句
     * @return CompletableFuture<QueryResult>
     */
    public CompletableFuture<QueryResult> queryStreamAsync(String sql) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                return grpcClient.queryStream(sql);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }, executorService);
    }
    
    /**
     * 创建查询构建器
     * @return QueryBuilder
     */
    public QueryBuilder queryBuilder() {
        return new QueryBuilder(this);
    }
    
    /**
     * 解析Line Protocol格式数据
     * @param lineProtocol Line Protocol字符串
     * @return DataPoint
     */
    public DataPoint parseLineProtocol(String lineProtocol) {
        return parser.parse(lineProtocol);
    }
    
    /**
     * 将数据点转换为Line Protocol格式
     * @param dataPoint 数据点
     * @return Line Protocol字符串
     */
    public String toLineProtocol(DataPoint dataPoint) {
        return parser.toLineProtocol(dataPoint);
    }
    
    /**
     * 检查连接状态
     * @return 是否已连接
     */
    public boolean isConnected() {
        return connected;
    }
    
    /**
     * 获取客户端配置
     * @return ClientConfig
     */
    public ClientConfig getConfig() {
        return config;
    }
    
    /**
     * 获取批量写入器
     * @return BatchWriter
     */
    public BatchWriter getBatchWriter() {
        return batchWriter;
    }
    
    /**
     * 健康检查
     * @return 是否健康
     */
    public boolean healthCheck() {
        try {
            return grpcClient.healthCheck();
        } catch (Exception e) {
            return false;
        }
    }
}
